package com.such.kit.ftp.support;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.tools.zip.ZipOutputStream;

import com.such.kit.Callable;
import com.such.kit.file.FileCommons;
import com.such.kit.file.bean.FileInfo;
import com.such.kit.file.support.FileFilter;

/**
 * @author SUCH
 * <pre>
 * FTP、FTPS、SFTP 工具类接口
 * </pre>
 */
public abstract class Ftp {

	protected String localCharset = "GBK";
	protected String ftpCharset = "ISO-8859-1";
	protected FileFilter fileFilter;

	/**
	 * <pre>
	 * 设置 FTP 额外参数
	 * </pre>
	 * @param key 键
	 * @param value 值
	 */
	public abstract void setProperty(String key, Object value);

	/**
	 * <pre>
	 * 链接并登录
	 * </pre>
	 * @param ip ip 地址
	 * @param port 端口
	 * @param username 用户名
	 * @param password 密码
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean connect(String ip, int port, String username, String password) throws Exception;

	/**
	 * <pre>
	 * 注销并关闭
	 * </pre>
	 * @throws Exception
	 */
	public abstract void logout() throws Exception;

	/**
	 * <pre>
	 * 重命名
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @param newName 新的名称
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean rename(String ftpPath, String newName) throws Exception;

	/**
	 * <pre>
	 * 创建文件夹
	 * </pre>
	 * @param ftpPath 文件夹路径
	 */
	public abstract void createFolder(String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 删除文件夹
	 * </pre>
	 * @param ftpPath 文件夹路径
	 */
	public abstract void deleteFolder(String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端文件夹下所有文件
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @param out 输出流
	 */
	public abstract void downloadFolder(String ftpPath, ZipOutputStream out) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端文件夹下所有文件
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @param zipParentPath zip 上级路径
	 * @param out 输出流
	 */
	public abstract void downloadFolder(String ftpPath, String zipParentPath, ZipOutputStream out) throws Exception;

	/**
	 * <pre>
	 * 列表 (S)FTP(S) 端文件夹下文件
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @param orderMode 排序模式
	 * @param isDesc 是否使用降序排列
	 * @return 文件列表
	 */
	public abstract List<FileInfo> listFolder(String ftpPath, String orderMode, boolean isDesc) throws Exception;

	/**
	 * <pre>
	 * 判断指定路径是否为文件夹
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean isFolder(String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 创建文件
	 * </pre>
	 * @param localIn 本地数据流
	 * @param ftpPath 文件路径
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean createFile(InputStream localIn, String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 创建文件
	 * </pre>
	 * @param localR 本地数据流
	 * @param ftpPath 文件路径
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean createFile(Reader localR, String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 删除文件
	 * </pre>
	 * @param ftpPath 文件路径
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean deleteFile(String ftpPath) throws Exception;

	/**
	 * <pre>
	 * 删除文件夹下所有文件
	 * </pre>
	 * @param ftpPath 文件夹路径
	 * @param containFolder 是否删除文件夹
	 */
	public abstract void deleteFiles(String ftpPath, boolean containFolder) throws Exception;

	/**
	 * <pre>
	 * 删除文件夹下所有文件
	 * </pre>
	 * @param fileInfoList 文件列表
	 * @param containFolder 是否删除文件夹
	 */
	public abstract void deleteFiles(List<FileInfo> fileInfoList, boolean containFolder) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端文件
	 * </pre>
	 * @param ftpPath 文件路径
	 * @param callable 回调
	 * @return callable 返回值
	 */
	public abstract <T> T downloadFile(String ftpPath, Callable<InputStream, T> callable) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端文件
	 * </pre>
	 * @param ftpPath 文件路径
	 * @param out 输出流
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean downloadFile(String ftpPath, OutputStream out) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端所有文件
	 * </pre>
	 * @param fileInfoList 文件列表
	 * @param out 输出流
	 */
	public abstract void downloadFiles(List<FileInfo> fileInfoList, ZipOutputStream out) throws Exception;

	/**
	 * <pre>
	 * 下载 (S)FTP(S) 端文件夹下所有文件
	 * </pre>
	 * @param fileInfoList 文件列表
	 * @param zipParentPath zip 上级路径
	 * @param out 输出流
	 */
	public abstract void downloadFiles(List<FileInfo> fileInfoList, String zipParentPath, ZipOutputStream out) throws Exception;

	/**
	 * <pre>
	 * 传输文件
	 * </pre>
	 * @param ftpPath ftp 文件路径
	 * @param targetFtp 目标 ftp
	 * @param targetPath 目标 ftp 路径
	 * @return 是否成功 [true 是]
	 */
	public abstract boolean transferFile(String ftpPath, final Ftp targetFtp, final String targetPath) throws Exception;

	/**
	 * <pre>
	 * 设置本地端编码，默认为 GBK
	 * </pre>
	 * @param localCharset 编码
	 */
	public void setLocalCharset(String localCharset) {
		this.localCharset = localCharset;
	}

	/**
	 * <pre>
	 * 设置 FTP 端编码，默认为 ISO-8859-1
	 * </pre>
	 * @param ftpCharset 编码
	 */
	public void setFtpCharset(String ftpCharset) {
		this.ftpCharset = ftpCharset;
	}

	/**
	 * <pre>
	 * 设置文件列表过滤器
	 * </pre>
	 * @param fileFilter 过滤器
	 */
	public void setFileFilter(FileFilter fileFilter) {
		this.fileFilter = fileFilter;
	}

	protected String encodeURI(String uri) throws UnsupportedEncodingException {
		return new String(FileCommons.changeCompatSeparator(uri).getBytes(localCharset), ftpCharset);
	}

}